package com.apigen.platform.util;

import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 数据库类型映射工具类
 *
 * @author API Generator Platform
 * @since 2025-10-03
 */
public class DatabaseTypeMapper {

    /**
     * 数据库类型到Java类型的映射
     */
    private static final Map<String, String> DB_TYPE_TO_JAVA_TYPE = new HashMap<>();

    /**
     * 数据库类型到JDBC类型的映射
     */
    private static final Map<String, String> DB_TYPE_TO_JDBC_TYPE = new HashMap<>();

    static {
        // 字符串类型
        DB_TYPE_TO_JAVA_TYPE.put("CHAR", "String");
        DB_TYPE_TO_JAVA_TYPE.put("VARCHAR", "String");
        DB_TYPE_TO_JAVA_TYPE.put("VARCHAR2", "String");
        DB_TYPE_TO_JAVA_TYPE.put("NVARCHAR", "String");
        DB_TYPE_TO_JAVA_TYPE.put("NVARCHAR2", "String");
        DB_TYPE_TO_JAVA_TYPE.put("TEXT", "String");
        DB_TYPE_TO_JAVA_TYPE.put("LONGTEXT", "String");
        DB_TYPE_TO_JAVA_TYPE.put("MEDIUMTEXT", "String");
        DB_TYPE_TO_JAVA_TYPE.put("TINYTEXT", "String");
        DB_TYPE_TO_JAVA_TYPE.put("CLOB", "String");
        DB_TYPE_TO_JAVA_TYPE.put("NCLOB", "String");

        // 整数类型
        DB_TYPE_TO_JAVA_TYPE.put("TINYINT", "Integer");
        DB_TYPE_TO_JAVA_TYPE.put("SMALLINT", "Integer");
        DB_TYPE_TO_JAVA_TYPE.put("MEDIUMINT", "Integer");
        DB_TYPE_TO_JAVA_TYPE.put("INT", "Integer");
        DB_TYPE_TO_JAVA_TYPE.put("INTEGER", "Integer");
        DB_TYPE_TO_JAVA_TYPE.put("BIGINT", "Long");
        DB_TYPE_TO_JAVA_TYPE.put("NUMBER", "Long");

        // 浮点数类型
        DB_TYPE_TO_JAVA_TYPE.put("FLOAT", "Float");
        DB_TYPE_TO_JAVA_TYPE.put("DOUBLE", "Double");
        DB_TYPE_TO_JAVA_TYPE.put("REAL", "Double");
        DB_TYPE_TO_JAVA_TYPE.put("DECIMAL", "BigDecimal");
        DB_TYPE_TO_JAVA_TYPE.put("NUMERIC", "BigDecimal");

        // 日期时间类型
        DB_TYPE_TO_JAVA_TYPE.put("DATE", "LocalDate");
        DB_TYPE_TO_JAVA_TYPE.put("TIME", "LocalTime");
        DB_TYPE_TO_JAVA_TYPE.put("DATETIME", "LocalDateTime");
        DB_TYPE_TO_JAVA_TYPE.put("TIMESTAMP", "LocalDateTime");
        DB_TYPE_TO_JAVA_TYPE.put("YEAR", "Integer");

        // 布尔类型
        DB_TYPE_TO_JAVA_TYPE.put("BIT", "Boolean");
        DB_TYPE_TO_JAVA_TYPE.put("BOOLEAN", "Boolean");
        DB_TYPE_TO_JAVA_TYPE.put("BOOL", "Boolean");

        // 二进制类型
        DB_TYPE_TO_JAVA_TYPE.put("BINARY", "byte[]");
        DB_TYPE_TO_JAVA_TYPE.put("VARBINARY", "byte[]");
        DB_TYPE_TO_JAVA_TYPE.put("LONGVARBINARY", "byte[]");
        DB_TYPE_TO_JAVA_TYPE.put("BLOB", "byte[]");
        DB_TYPE_TO_JAVA_TYPE.put("LONGBLOB", "byte[]");
        DB_TYPE_TO_JAVA_TYPE.put("MEDIUMBLOB", "byte[]");
        DB_TYPE_TO_JAVA_TYPE.put("TINYBLOB", "byte[]");

        // JDBC类型映射
        DB_TYPE_TO_JDBC_TYPE.put("CHAR", "CHAR");
        DB_TYPE_TO_JDBC_TYPE.put("VARCHAR", "VARCHAR");
        DB_TYPE_TO_JDBC_TYPE.put("VARCHAR2", "VARCHAR");
        DB_TYPE_TO_JDBC_TYPE.put("NVARCHAR", "NVARCHAR");
        DB_TYPE_TO_JDBC_TYPE.put("TEXT", "LONGVARCHAR");
        DB_TYPE_TO_JDBC_TYPE.put("LONGTEXT", "LONGVARCHAR");
        
        DB_TYPE_TO_JDBC_TYPE.put("TINYINT", "TINYINT");
        DB_TYPE_TO_JDBC_TYPE.put("SMALLINT", "SMALLINT");
        DB_TYPE_TO_JDBC_TYPE.put("INT", "INTEGER");
        DB_TYPE_TO_JDBC_TYPE.put("INTEGER", "INTEGER");
        DB_TYPE_TO_JDBC_TYPE.put("BIGINT", "BIGINT");
        DB_TYPE_TO_JDBC_TYPE.put("NUMBER", "NUMERIC");
        
        DB_TYPE_TO_JDBC_TYPE.put("FLOAT", "FLOAT");
        DB_TYPE_TO_JDBC_TYPE.put("DOUBLE", "DOUBLE");
        DB_TYPE_TO_JDBC_TYPE.put("DECIMAL", "DECIMAL");
        DB_TYPE_TO_JDBC_TYPE.put("NUMERIC", "NUMERIC");
        
        DB_TYPE_TO_JDBC_TYPE.put("DATE", "DATE");
        DB_TYPE_TO_JDBC_TYPE.put("TIME", "TIME");
        DB_TYPE_TO_JDBC_TYPE.put("DATETIME", "TIMESTAMP");
        DB_TYPE_TO_JDBC_TYPE.put("TIMESTAMP", "TIMESTAMP");
        
        DB_TYPE_TO_JDBC_TYPE.put("BIT", "BIT");
        DB_TYPE_TO_JDBC_TYPE.put("BOOLEAN", "BOOLEAN");
        
        DB_TYPE_TO_JDBC_TYPE.put("BINARY", "BINARY");
        DB_TYPE_TO_JDBC_TYPE.put("VARBINARY", "VARBINARY");
        DB_TYPE_TO_JDBC_TYPE.put("BLOB", "BLOB");
    }

    /**
     * 将数据库类型映射为Java类型
     *
     * @param dbType 数据库类型
     * @param length 字段长度
     * @param precision 精度
     * @return Java类型
     */
    public static String mapToJavaType(String dbType, Integer length, Integer precision) {
        if (!StringUtils.hasText(dbType)) {
            return "String";
        }

        String normalizedType = dbType.toUpperCase().trim();
        
        // 处理特殊情况
        if (normalizedType.startsWith("TINYINT(1)") || normalizedType.equals("TINYINT(1)")) {
            return "Boolean"; // MySQL中TINYINT(1)通常用作布尔类型
        }
        
        if (normalizedType.startsWith("DECIMAL") || normalizedType.startsWith("NUMERIC")) {
            if (precision != null && precision == 0) {
                if (length != null && length <= 10) {
                    return "Integer";
                } else {
                    return "Long";
                }
            }
            return "BigDecimal";
        }

        // 从映射表中查找
        String javaType = DB_TYPE_TO_JAVA_TYPE.get(normalizedType);
        return javaType != null ? javaType : "String";
    }

    /**
     * 将数据库类型映射为JDBC类型
     *
     * @param dbType 数据库类型
     * @return JDBC类型
     */
    public static String mapToJdbcType(String dbType) {
        if (!StringUtils.hasText(dbType)) {
            return "VARCHAR";
        }

        String normalizedType = dbType.toUpperCase().trim();
        String jdbcType = DB_TYPE_TO_JDBC_TYPE.get(normalizedType);
        return jdbcType != null ? jdbcType : "VARCHAR";
    }

    /**
     * 获取Java类型对应的默认值
     *
     * @param javaType Java类型
     * @return 默认值字符串
     */
    public static String getDefaultValue(String javaType) {
        switch (javaType) {
            case "String":
                return "\"\"";
            case "Integer":
            case "Long":
            case "Float":
            case "Double":
                return "0";
            case "BigDecimal":
                return "BigDecimal.ZERO";
            case "Boolean":
                return "false";
            case "LocalDate":
                return "LocalDate.now()";
            case "LocalTime":
                return "LocalTime.now()";
            case "LocalDateTime":
                return "LocalDateTime.now()";
            case "byte[]":
                return "new byte[0]";
            default:
                return "null";
        }
    }

    /**
     * 获取Java类型需要的导入语句
     *
     * @param javaType Java类型
     * @return 导入语句，如果不需要导入则返回null
     */
    public static String getImportStatement(String javaType) {
        switch (javaType) {
            case "BigDecimal":
                return "java.math.BigDecimal";
            case "LocalDate":
                return "java.time.LocalDate";
            case "LocalTime":
                return "java.time.LocalTime";
            case "LocalDateTime":
                return "java.time.LocalDateTime";
            default:
                return null;
        }
    }

    /**
     * 判断是否为数值类型
     *
     * @param javaType Java类型
     * @return 是否为数值类型
     */
    public static boolean isNumericType(String javaType) {
        return "Integer".equals(javaType) || "Long".equals(javaType) || 
               "Float".equals(javaType) || "Double".equals(javaType) || 
               "BigDecimal".equals(javaType);
    }

    /**
     * 判断是否为日期时间类型
     *
     * @param javaType Java类型
     * @return 是否为日期时间类型
     */
    public static boolean isDateTimeType(String javaType) {
        return "LocalDate".equals(javaType) || "LocalTime".equals(javaType) || 
               "LocalDateTime".equals(javaType);
    }

    /**
     * 判断是否为字符串类型
     *
     * @param javaType Java类型
     * @return 是否为字符串类型
     */
    public static boolean isStringType(String javaType) {
        return "String".equals(javaType);
    }

    /**
     * 获取字段的验证注解
     *
     * @param javaType Java类型
     * @param nullable 是否可为空
     * @param length 字段长度
     * @param precision 精度
     * @param scale 小数位数
     * @return 验证注解列表
     */
    public static String[] getValidationAnnotations(String javaType, boolean nullable, 
                                                   Integer length, Integer precision, Integer scale) {
        if (nullable) {
            return new String[0]; // 可为空则不需要验证注解
        }

        switch (javaType) {
            case "String":
                if (length != null && length > 0) {
                    return new String[]{
                        "@NotBlank(message = \"不能为空\")",
                        "@Size(max = " + length + ", message = \"长度不能超过" + length + "个字符\")"
                    };
                } else {
                    return new String[]{"@NotBlank(message = \"不能为空\")"};
                }
            case "Integer":
            case "Long":
            case "Float":
            case "Double":
            case "BigDecimal":
                return new String[]{"@NotNull(message = \"不能为空\")"};
            case "LocalDate":
            case "LocalTime":
            case "LocalDateTime":
                return new String[]{"@NotNull(message = \"不能为空\")"};
            default:
                return new String[]{"@NotNull(message = \"不能为空\")"};
        }
    }
}
